package schoolMatSupport;

import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;
import core.SchoolMat;
import dao.SchoolMatDAO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import org.artofsolving.jodconverter.office.OfficeManager;

/**
 * @author Michal Horak
 * @version 1.0
 */
@Stateless
public class PDFReader implements IReader {

    private int pageCount = 0;
    private String imgLabel;
    private PDFFile pdffile;
    private double documentOriginWidth = 0;
    private double documentOriginHeight = 0;
    private RandomAccessFile raf;
    private File file;
    private ConvertFileToPDF convertor = new ConvertFileToPDF();
    private String serverPath;
    SchoolMat material = null;

    public PDFReader() {
    }

    // This method returns a buffered image with the contents of an image
    /**
     *
     * @param image
     * @return BufferedImage
     */
    public static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }
        // This code ensures that all the pixels in the image are loaded
        image = new ImageIcon(image).getImage();
        // Determine if the image has transparent pixels; for this method's
        // implementation, see e661 Determining If an Image Has Transparent
        // Pixels
        boolean hasAlpha = hasAlpha(image);
        // Create a buffered image with a format that's compatible with the
        // screen
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            // Determine the type of transparency of the new buffered image
            int transparency = Transparency.OPAQUE;
            if (hasAlpha) {
                transparency = Transparency.BITMASK;
            }
            // Create the buffered image
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            throw new RuntimeException(e.getMessage());
        }
        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            if (hasAlpha) {
                type = BufferedImage.TYPE_INT_ARGB;
            }
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }
        // Copy image to buffered image
        Graphics g = bimage.createGraphics();
        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }

    public static boolean hasAlpha(Image image) {
        // If buffered image, the color model is readily available
        if (image instanceof BufferedImage) {
            BufferedImage bimage = (BufferedImage) image;
            return bimage.getColorModel().hasAlpha();
        }
        // Use a pixel grabber to retrieve the image's color model;
        // grabbing a single pixel is usually sufficient
        PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
        }
        // Get the image's color model
        ColorModel cm = pg.getColorModel();
        return cm.hasAlpha();
    }

    @Override
    public void closeDocument() {
        if (getConnection() != null) {
            getConnection().stop();
        }

        if (raf != null) {
            try {
                raf.close();
            } catch (IOException ex) {
                throw new RuntimeException(ex.getMessage());
            }
        }
        System.gc();
    }

    @Override
    public String getPage(final int i) throws RuntimeException {
        //budu vytvaret pouze pokud stranka jeste nebyla vygenerovana
        File check = new File(serverPath + "resources/materials" + File.separator + material.getCheckSum()
                + File.separator + material.getCheckSum() + "full_" + i + ".png");

        if (!check.exists()) {
            if (pdffile != null) {
                PDFPage page = pdffile.getPage(i);
                
                if (page == null){
                    return "resources";
                }
                Rectangle rect = new Rectangle(0, 0, (int) page.getWidth(), (int) page.getHeight());

                BufferedImage bImg = null;
                if (page != null) {
                    try {
                        Image img = page.getImage((int) (rect.width * 1.8), (int) (rect.height * 1.8), rect, null, true, true);
                        bImg = toBufferedImage(img);
                    } catch (OutOfMemoryError e) {
                        System.gc();
                        throw new RuntimeException("nelze nacist " + e.getMessage());
                    } catch (RuntimeException ex) {
                        throw ex;
                    } catch (Exception ex) {
                        throw new RuntimeException("nelze nacist " + ex.getMessage());
                    }
                }

                File fileDir = new File(serverPath + "resources/materials" + File.separator + material.getCheckSum());

                if (bImg != null) {
                    try {
                        ImageIO.write(bImg, "png", new File(fileDir.getPath()
                                + File.separator + material.getCheckSum() + "full_" + i + ".png"));
                    } catch (IOException ex) {
                        throw new RuntimeException("nelze nacist " + ex.getMessage());
                    }
                }

                imgLabel = "resources/materials/" + material.getCheckSum() + File.separator + material.getCheckSum()
                        + "full_" + i + ".png";


                if (documentOriginHeight == 0) {
                    documentOriginWidth = bImg.getWidth();
                }
                if (documentOriginHeight == 0) {
                    documentOriginHeight = bImg.getHeight();
                }
            }
        } else {
            imgLabel = "resources/materials/" + material.getCheckSum() + File.separator + material.getCheckSum()
                    + "full_" + i + ".png";
        }

        return imgLabel;

    }

    @Override
    public double getDocumentWidth() {
        return documentOriginWidth;
    }

    @Override
    public double getDocumentHeight() {
        return documentOriginHeight;
    }

    @Override
    public int getTotalPages() {
        return pageCount;
    }

    @Override
    public File getFile() {
        return this.file;
    }

    @Override
    public void openDocument(SchoolMat mat, String serverPath, String filePath) {
        this.file = new File(filePath);
        this.serverPath = serverPath;
        this.material = mat;

        String checkSum = mat.getCheckSum();

        if (!file.exists()) {
            throw new RuntimeException("Soubor nenalezen");
        } else {
            if (checkSum.isEmpty()) {
                try {
                    checkSum = MD5Checksum.getMD5Checksum(filePath);
                    SchoolMatDAO dao = new SchoolMatDAO();
                    mat.setCheckSum(checkSum);
                    dao.updateSchoolMat(mat);
                } catch (Exception ex) {
                    //TODO
                    //Logger.getLogger(PDFReader.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        //v pripade, ze soubor neni pdf, je potreba ho prevest
        File fileDir = new File(serverPath + "resources/materials" + File.separator + checkSum);

        if (!fileDir.exists()) {
            fileDir.mkdir();
        }

        final File outputFile = new File(fileDir.getPath() + File.separator + checkSum + "_tmp.pdf");

        if (!outputFile.exists()) {
            if (!file.getName().endsWith(".pdf")) {
                try {
                    if (convertor.isSupported(file)) {
                        try {
                            File tempPdf = convertor.fileToPDF(checkSum, serverPath, file);
                            this.file = tempPdf;

                        } catch (Exception ex) {
                            setNull();
                            throw new RuntimeException(ex.getMessage());
                        }
                    } else {
                        throw new RuntimeException("Nepodporovany soubor");
                    }

                } catch (Exception e) {
                    throw new RuntimeException(e.getMessage());
                }
            }
        } else {
            this.file = outputFile;
        }

        try {
            raf = new RandomAccessFile(file, "r");

            FileChannel channel = raf.getChannel();
            ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
            pdffile = new PDFFile(buf);
            pageCount = pdffile.getNumPages();

            raf.close();

        } catch (FileNotFoundException ex) {
            throw new RuntimeException(ex.getMessage());
        } catch (IOException ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }

    private final void setNull() {
        closeDocument();

        if (convertor.getConnection() != null) {
            convertor.getConnection().stop();
        }
    }

    private OfficeManager getConnection() {
        return convertor.getConnection();
    }

    @Override
    public List<String> getThumbnails() {
        //TODO dodelat kontrolni soucty
        List<String> list = new ArrayList<String>();

        for (int i = 1; i <= pageCount; i++) {
            File test = new File(serverPath + File.separator + "resources/materials/"
                    + material.getCheckSum() + File.separator + material.getCheckSum() + "_th" + i + ".png");
            if (test.exists()) {
                list.add("resources/materials/" + material.getCheckSum()
                        + File.separator + material.getCheckSum() + "_th" + i + ".png");
                continue;
            }

            PDFPage page = pdffile.getPage(i);
            Rectangle rect = new Rectangle(0, 0, (int) page.getWidth(), (int) page.getHeight());
            // generate the image

            BufferedImage bImg = null;
            if (page != null && page != null) {
                try {
                    Image img = page.getImage(rect.width / 3, rect.height / 3, rect, null, true, true);
                    bImg = toBufferedImage(img);
                } catch (OutOfMemoryError ex) {
                    System.out.println("Chyba2");
                } catch (RuntimeException ex) {
                    System.out.println("Chyba1");
                }

            }
            if (bImg != null) {
                try {
                    ImageIO.write(bImg, "png", new File(serverPath + File.separator + "resources/materials/"
                            + material.getCheckSum() + File.separator + material.getCheckSum() + "_th" + i + ".png"));
                } catch (IOException ex) {
                    throw new RuntimeException("nelze nacist " + ex.getMessage());
                }
            }


            list.add("resources/materials/" + material.getCheckSum()
                    + File.separator + material.getCheckSum() + "_th" + i + ".png");
        }
        return list;
    }
}
